#include "parameter/parameters.h"
#include "platform.h"

struct param_s g_parameters[] = {
	PARAM_DEFINE(ROLL_RATE_P, PARAM_FLOAT),
	PARAM_DEFINE(ROLL_RATE_I, PARAM_FLOAT),
	PARAM_DEFINE(ROLL_RATE_D, PARAM_FLOAT),
	PARAM_DEFINE(PITCH_RATE_P, PARAM_FLOAT),
	PARAM_DEFINE(PITCH_RATE_I, PARAM_FLOAT),
	PARAM_DEFINE(PITCH_RATE_D, PARAM_FLOAT),
	PARAM_DEFINE(YAW_RATE_P, PARAM_FLOAT),
	PARAM_DEFINE(YAW_RATE_I, PARAM_FLOAT),
	PARAM_DEFINE(YAW_RATE_D, PARAM_FLOAT),
	PARAM_DEFINE(RC_CH1_MIN, PARAM_UINT16),
	PARAM_DEFINE(RC_CH1_MAX, PARAM_UINT16),
	PARAM_DEFINE(RC_CH1_MID, PARAM_UINT16),
	PARAM_DEFINE(RC_CH2_MIN, PARAM_UINT16),
	PARAM_DEFINE(RC_CH2_MAX, PARAM_UINT16),
	PARAM_DEFINE(RC_CH2_MID, PARAM_UINT16),
	PARAM_DEFINE(RC_CH3_MIN, PARAM_UINT16),
	PARAM_DEFINE(RC_CH3_MAX, PARAM_UINT16),
	PARAM_DEFINE(RC_CH3_MID, PARAM_UINT16),
	PARAM_DEFINE(RC_CH4_MIN, PARAM_UINT16),
	PARAM_DEFINE(RC_CH4_MAX, PARAM_UINT16),
	PARAM_DEFINE(RC_CH4_MID, PARAM_UINT16),
	PARAM_DEFINE(MAG_SCALE_X, PARAM_FLOAT),
	PARAM_DEFINE(MAG_SCALE_Y, PARAM_FLOAT),
	PARAM_DEFINE(MAG_SCALE_Z, PARAM_FLOAT),
	PARAM_DEFINE(MAG_OFFSET_X, PARAM_FLOAT),
	PARAM_DEFINE(MAG_OFFSET_Y, PARAM_FLOAT),
	PARAM_DEFINE(MAG_OFFSET_Z, PARAM_FLOAT),
	PARAM_DEFINE(ACC_SCALE_X, PARAM_FLOAT),
	PARAM_DEFINE(ACC_SCALE_Y, PARAM_FLOAT),
	PARAM_DEFINE(ACC_SCALE_Z, PARAM_FLOAT),
	PARAM_DEFINE(ACC_OFFSET_X, PARAM_FLOAT),
	PARAM_DEFINE(ACC_OFFSET_Y, PARAM_FLOAT),
	PARAM_DEFINE(ACC_OFFSET_Z, PARAM_FLOAT)
};

uint8_t param_save(enum param_index paramIdx)
{
	uint8_t wordsOfParam = 0;
	void *pVar = g_parameters[paramIdx].val_ptr;

	if (g_parameters[paramIdx].val_ptr == 0)
		return 0;
	switch (g_parameters[paramIdx].type) {
	case PARAM_INT32:
	case PARAM_FLOAT:
		wordsOfParam = 2;
		break;
	case PARAM_UINT16:
		wordsOfParam = 1;
		break;
	default:
		break;
	}

	if (wordsOfParam == 0 || wordsOfParam > 2)
		return 0;
	if (wordsOfParam == 1)
		board_write_flash(paramIdx * 2, *(uint16_t *)pVar);
	else {
		board_write_flash(paramIdx * 2, *(uint16_t *)pVar);
		board_write_flash(paramIdx * 2 + 1, *((uint16_t *)pVar + 1));
	}
	return 1;
}

uint8_t param_load(enum param_index paramIdx)
{
	uint8_t wordsOfParam = 0;
	void *pVar = g_parameters[paramIdx].val_ptr;

	if (g_parameters[paramIdx].val_ptr == 0)
		return 0;
	switch (g_parameters[paramIdx].type) {
	case PARAM_INT32:
	case PARAM_FLOAT:
		wordsOfParam = 2;
		break;
	case PARAM_UINT16:
		wordsOfParam = 1;
		break;
	default:
		break;
	}

	if (wordsOfParam == 0 || wordsOfParam > 2)
		return 0;
	if (wordsOfParam == 1)
		*(uint16_t *)pVar = board_read_flash(paramIdx * 2);
	else {
		*(uint16_t *)pVar = board_read_flash(paramIdx * 2);
		*((uint16_t *)pVar + 1) = board_read_flash(paramIdx * 2 + 1);
	}
	return 1;
}

/*
 * @brief load all parameters
 * @param none
 * @retval
 * 	the number of successfully loaded parameters.
 */
uint16_t param_load_all(void)
{
	uint16_t total_num = sizeof(g_parameters)/sizeof(g_parameters[0]);
	uint16_t saved_num = 0;
	uint16_t i;

	for (i = 0; i < total_num; i++) {
		if (param_load(i)) {
			saved_num++;
		}
	}
	return saved_num;
}

/*
 * @brief load one parameter at each call
 * @param
 * 	none
 * @retval
 * 	0 	all parameters have been loaded,
 * 		will start from the first one at next call.
 * 	1	still has parameters to load.
 */
uint8_t param_load_one_by_one(void)
{
	static uint16_t idx = 0;
	uint16_t total_num = sizeof(g_parameters)/sizeof(g_parameters[0]);

	param_load(idx++);

	if (idx >= total_num) {
		idx = 0;
		return 0;
	}
	return 1;
}
